
module jade.tpl.js.Tpl;

import jade.tpl.Template ;

static DTpl_Constructor	tpl_constructor ;
static DTpl_Prototype		tpl_prototype ;
static DJade_Prototype		jade_prototype ;


final class DTpl_Constructor : Dfunction {

	final this() {
		super(2, Dfunction_prototype);
		
		static enum NativeFunctionData nfd[] =
		[
		    {"Read", &Tpl_property_Read, 0} ,
		    {"Jade", &Tpl_property_Jade, 1} ,
		];

		DnativeFunction.init(this, nfd, 0 );
	}
	

	final override void* Construct(CallContext *cc, Value *ret, Value[] arg)
	{
		return null;
	}
	
	final override void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist){
		// log(" Call");
		return null;
	}
	
	static void* Tpl_property_Read(Dobject pthis, CallContext* cc, Dobject othis, Value* ret, Value[] argv){
		if( argv.length is 0 || !argv[0].isString ) {
			return null;
		}
		string path = argv[0].toString ;
		if( !std.file.exists(path) || !isFile(path) ){
			return null;
		}
		string ext = std.path.getExt(path);
		if( icmp(ext, `jade`) is 0 || icmp(ext, `tpl`) is 0 ) {
			try{
				string data = cast(string) std.file.read(path);
				ret.putVstring(data);
			}catch(Exception e){
				
			}
		}
		return null;
	}
	
	static void* Tpl_property_Jade(Dobject pthis, CallContext* cc, Dobject othis, Value* ret, Value[] args) {
		auto jade	= new DJade_Object(jade_prototype) ;
		jade.initialize(args);
		ret.putVobject( jade );
		return null;
	}
}


final class DTpl_Prototype : Dobject {

	final this(Dobject prototype){
		super(prototype);
		
		static enum NativeFunctionData nfd[] =
		[
		    
		];

		DnativeFunction.init(this, nfd, DontEnum | DontDelete | ReadOnly );
	}
	
}

final class DTpl_Object : Dobject {
	
	string			tpl_name ;
	DVars_Object		vars ;
	Dobject			options ;
	DJade_Object		jade ;
	
	final this(Dobject prototype){
		super(prototype);
		
		static enum NativeFunctionData nfd[] =
		[
		    
		];

		DnativeFunction.init(this, nfd, DontEnum | DontDelete | ReadOnly );
		
		vars	= new DVars_Object(Dobject_prototype) ;
		options	= new Dobject(Dobject_prototype) ;
		
		Put("vars", vars, DontEnum | DontDelete | ReadOnly );
		Put("options", options, DontEnum | DontDelete | ReadOnly );
		
		jade	= new DJade_Object(jade_prototype) ;
		jade.initialize(null);
		
		initialize();
	}
	
	final void call_method(string method)(){
		auto value 	=  this.Get(method) ;
		assert(value !is null);
		auto fun	= value.toObject ;
		assert(fun !is null);
		Value 	ret;
		Value[]	args ;
		auto _ret = cast(Value*) fun.Call( Tpl_Factory.program.callcontext, this, &ret, args );
		if( _ret !is null ){
			Log( _ret.toString );
			assert(false);
		}
	}
	
	alias call_method!("initialize") initialize ;
	
	final string render(bool _recompile = false ) {
		return jade.render(vars, _recompile) ;
	}
	
	final typeof(this) assign(T)(T* v, string name ) if( is(T==struct)){
		alias JType!(T) T_;
		T_.Init(Tpl_Factory.program);
		vars.Put(name,  new T_(v), 0 );
		return this;
	}
	
	final typeof(this) assign(T)(T v, string name ) if(   is(T==class)  ){
		alias JType!(T) T_;
		T_.Init(Tpl_Factory.program);
		vars.Put(name,  new T_(v), 0 );
		return this;
	}
	
	final typeof(this) assign(T)(T v, string name ) if( isSomeString!(T) || std.traits.isNumeric!(T) || is(T==bool)  ){
		static if( is(T==bool) ){
			vars.Put(name,  v, 0);
		} else static if(isSomeString!(T)){
			vars.Put(name,  v, 0);
		} else static if( std.traits.isNumeric!(T)  ){
			vars.Put(name,  v, 0);
		} else {
			assert(false);
		}
		return this;
	}
	
	final typeof(this) assign(T)(in T[] list, string name ) if(is(T==struct)  || is(T==class) || (isPointer!(T) && is(pointerTarget!(T)==struct) ) ){
		static if( is(T==class) || is(T==struct)  ) {
			alias T T1;
		} else	static if( isPointer!(T) ) {
			alias pointerTarget!(T) T1;
		}
		alias JType!(T1) T_;
		T_.Init(Tpl_Factory.program);
		
		Darray a = new Darray ;
		if( list !is null && list.length > 0 ){
			Value[] _list = new Value[ list.length] ;
			foreach(int i, ref v; list){
				static if( is(T==struct)){
					_list[i].putVobject( new T_.Obj(cast(T*)&v) ) ;
				} else static if( is(T==class) || isPointer!(T) ){
					if( v !is null) {
						_list[i].putVobject( new T_( cast(T)v) ) ;
					}
				}
				a.Put(i, &_list[i], 0);
			}
		}
		vars.Put(name, a, 0 );
		return this;
	}
	
	final typeof(this) assign(T)(T[] list, string name ) if( isSomeString!(T) || std.traits.isNumeric!(T) || is(T==bool) ){
		Darray a = new Darray ;
		if( list !is null && list.length > 0 ){
			Value[] _list = new Value[ list.length] ;
			foreach(int i, ref v; list){
				static if(isSomeString!(T)){
					_list[i].putVstring(v);
				} else static if( std.traits.isNumeric!(T)){
					_list[i].putVnumber(v);
				} else static if( is(T==bool)){
					_list[i].putVbool(v);
				}else{
					static assert(false);
				}
				a.Put(i, &_list[i], 0);
			}
		}
		vars.Put(name, a, 0 );
		return this;
	}
	
	final typeof(this) assign(T, K)(T[K] list, string name ) if( ( isSomeString!(K)  || isNumeric!(T) ) && (  isSomeString!(K)  || isNumeric!(T) ||  is(T==bool) || is(T==class) || is(T==struct) || ( isPointer!(T) && is(pointerTarget!(T)==struct) ) )  ){
		alias JAA!(K,T) _AAtype;
		auto obj = new _AAtype(list);
		vars.Put(name, obj, 0 );
		return this;
	}
	
	
	static void Init(Dobject obj){
		if( tpl_constructor !is null ) {
			return ;
		}
		
		DBuffer_Object.Init(obj);
		
		tpl_constructor		= new DTpl_Constructor ;
		tpl_prototype		= new DTpl_Prototype(Dobject_prototype) ;
		jade_prototype		= new DJade_Prototype(Dobject_prototype) ;
      		tpl_constructor.Put(TEXT_prototype, tpl_prototype, DontEnum | DontDelete | ReadOnly);
		obj.Put("Tpl", tpl_constructor, DontEnum | DontDelete | ReadOnly);
		
		DStopWatch_Object.Init(obj);
	}
	
}




